package com.bl.student.manager.filters;

import com.bl.student.common.ApiResponseBody;
import com.bl.student.common.ApiResponseCode;
import com.bl.student.common.utils.CommonUtils;
import com.bl.student.common.utils.JSONUtil;
import com.bl.student.dao.redis.AdminInfoDao;
import com.bl.student.dao.redis.model.AdminInfo;
import com.google.common.base.Optional;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.logging.log4j.core.config.Order;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

/**
 * Created by yujingyi on 2017/07/08.
 */
@Log4j2
@WebFilter(
        filterName = "authFilter",
        urlPatterns = "/student/manager/*",
        initParams = {
                @WebInitParam(name = "excludePath", value = "/student/manager/login," +
                        "/student/manager/logout," +
                        "/student/manager/register," +
                        "/student/manager/get_captcha," +
                        "/student/manager/reset"),
        })
@Order(2)
public class AuthFilter implements Filter {

    @Autowired
    AdminInfoDao adminInfoDao;

    private FilterConfig filterConfig;
    private List<String> excludePath;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
        String excludePaths = this.filterConfig.getInitParameter("excludePath");
        if(!Strings.isNullOrEmpty(excludePaths)){
            excludePath = Splitter.on(',')
                    .omitEmptyStrings()
                    .trimResults()
                    .splitToList(excludePaths);
        }
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)throws IOException, ServletException {
        // if need not filter
        if (!needFilter(request)) {
            filterChain.doFilter(request, response);
            return;
        }

        String token = getToken((HttpServletRequest) request);
        if (Strings.isNullOrEmpty(token)) {
            denyAccess(response);
            return;
        }
        Optional<AdminInfo> adminInfoOptional = adminInfoDao.getAdminInfoByAuthCookie(token);

        if (adminInfoOptional.isPresent()) {
            setUserInfo(request, adminInfoOptional.get());
        } else {
            denyAccess(response);
            return;
        }

        filterChain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }

    private boolean needFilter(ServletRequest request) {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        // get request url
        String reqUrl = httpServletRequest.getRequestURI().replace(
                httpServletRequest.getContextPath(), "");
        for(String path : excludePath){
            if(reqUrl.startsWith(path)){
                return false;
            }
        }
        return true;
    }

    private void denyAccess(ServletResponse response) {

        try {
            PrintWriter outWriter = response.getWriter();
            outWriter.print(
                    JSONUtil.jsonEncode(
                            ApiResponseBody.createErrorBody(ApiResponseCode.NOT_AUTHORIZED.getCode(),
                                    ApiResponseCode.NOT_AUTHORIZED.getMsg())));
        } catch (IOException e) {
            log.error(ExceptionUtils.getRootCauseMessage(e));
        }
    }

    private String getToken(HttpServletRequest httpServletRequest) {
        Optional<Cookie> cookieOptional = getCookie(httpServletRequest, CommonUtils.ADMIN_TOKEN_KEY);

        if (cookieOptional.isPresent()) {
            return cookieOptional.get().getValue();
        } else if (!Strings.isNullOrEmpty(httpServletRequest.getParameter(CommonUtils.TOKEN_PARAM))){
            return httpServletRequest.getParameter(CommonUtils.TOKEN_PARAM);
        } else {
            log.warn("no token is found, request: {}", httpServletRequest);
            return null;
        }

    }

    private Optional<Cookie> getCookie(HttpServletRequest httpServletRequest, String cookieName) {

        final Cookie[] cookies = httpServletRequest.getCookies();
        if (cookies != null && cookies.length > 0){
            for (Cookie cookie : cookies){
                if (cookieName.equals(cookie.getName())){
                    return Optional.fromNullable(cookie);
                }
            }
        }
        return Optional.absent();
    }

    private void setUserInfo(ServletRequest request, AdminInfo userInfo) {
        request.setAttribute(CommonUtils.CURRENT_USER_INFO, userInfo);
    }


}
